-- Copyright James McGill, 2010
-- Author: James McGill (jmcgill@plexer.net)

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
 
ENTITY video_buffer_test IS
END video_buffer_test;
 
ARCHITECTURE behavior OF video_buffer_test IS 
 
    -- Component Declaration for the Unit Under Test (UUT)
 
    COMPONENT video_buffer
    PORT(
	      reset : IN std_logic;
         clock_8mhz : IN  std_logic;
         clock_24mhz : IN  std_logic;
			hframe : IN std_logic;
			vframe : IN std_logic;
         data : IN  std_logic_vector(7 downto 0);
         address : OUT  std_logic_vector(15 downto 0);
         pixel : OUT  std_logic_vector(3 downto 0);
			buffer1 : OUT std_logic_vector(7 downto 0);
			buffer2 : OUT std_logic_vector(7 downto 0);
			buffer3 : OUT std_logic_vector(7 downto 0);
			buffer4 : OUT std_logic_vector(7 downto 0);
         shift_buffer_out : out std_logic_vector(7 downto 0);
			read_index_out : out std_logic_vector(7 downto 0);
         write_index_out : out std_logic_vector(7 downto 0);
         buffer_count_out : out std_logic_vector(7 downto 0);
         decrement_out : out std_logic		
        );
    END COMPONENT;
    

   --Inputs
	signal reset : std_logic := '0';
   signal clock_8mhz : std_logic := '0';
   signal clock_24mhz : std_logic := '0';
	signal hsync : std_logic := '1';
	signal vsync : std_logic := '1';
   signal data : std_logic_vector(7 downto 0) := (others => '0');

 	--Outputs
   signal address : std_logic_vector(15 downto 0);
   signal pixel : std_logic_vector(3 downto 0);
	signal buffer1 : std_logic_vector(7 downto 0);
	signal buffer2 : std_logic_vector(7 downto 0);
	signal buffer3 : std_logic_vector(7 downto 0);
	signal buffer4 : std_logic_vector(7 downto 0);
	signal shift_buffer_out : std_logic_vector(7 downto 0);
	signal buffer_count_out : std_logic_vector(7 downto 0);
	signal decrement_out : std_logic;
	signal read_index_out : std_logic_vector(7 downto 0);
   signal write_index_out : std_logic_vector(7 downto 0);
	
	signal expected_pixel : std_logic := '0';
	
	signal write_minus_read : integer range -128 to 128;

   -- Clock period definitions
   
	-- NOTE(jmcgill): Now 16 Mhz.
	constant clock_8mhz_period : time := 62500 ps;
	--constant clock_8mhz_period : time := 62.5 ns;
   constant clock_24mhz_period : time := 20 ns;
 
BEGIN
 
	-- Instantiate the Unit Under Test (UUT)
   uut: video_buffer PORT MAP (
          reset => reset,
			 clock_8mhz => clock_8mhz,
          clock_24mhz => clock_24mhz,
			 hframe => hsync,
			 vframe => vsync,
          data => data,
          address => address,
          pixel => pixel,
			 buffer1 => buffer1,
			 buffer2 => buffer2,
			 buffer3 => buffer3,
			 buffer4 => buffer4,
          shift_buffer_out => shift_buffer_out,
			 write_index_out => write_index_out,
			 read_index_out => read_index_out,
          buffer_count_out => buffer_count_out,
          decrement_out => decrement_out		 
        );

   -- Clock process definitions
   clock_8mhz_process :process
   begin
	   data <= x"AA";
		--data <= std_logic_vector(unsigned(data) + 1);
		clock_8mhz <= '1';
		wait for clock_8mhz_period / 2;
		clock_8mhz <= '0';
		wait for clock_8mhz_period / 2;
   end process;
 
   clock_24mhz_process :process
   	variable enabled : std_logic := '0';
	begin
		clock_24mhz <= '1';
		wait for clock_24mhz_period / 2;
		clock_24mhz <= '0';
		wait for clock_24mhz_period / 2;
		
		-- Ignore leading undefined pixels
		if (pixel(0) = '0' or pixel(0) = '1') then
		  enabled := '1';
		end if;
		
		if (enabled = '1') then
		  -- Verify output. Should be shifted version of AA so will alternate
		  -- between 0 and 1.
		  assert(pixel(0) = expected_pixel);
		  expected_pixel <= not expected_pixel;
		  
		  -- Assert that the buffer never under or overflows.
		  assert(unsigned(buffer_count_out) > 0) report "Buffer underflow";
		  assert(unsigned(buffer_count_out) <= 30) report "Buffer overflow";
		  write_minus_read <= abs(to_integer(signed('0' & write_index_out)) - to_integer(signed('0' & read_index_out)));
		  assert(write_minus_read > 3) report "Address collision";
		end if;
   end process;
 
   -- Stimulus process
   stim_proc: process
   begin
	   reset <= '0';
		hsync <= '1';
		vsync <= '1';
		wait for clock_24mhz_period * 10;
      reset <= '1';
		wait;
   end process;

END;
